package Farsail::DBLoader;

use strict; 
use warnings;

use Carp;
use Path::Class qw();
use File::Temp qw(tempfile);

my ($farsail, $logger);

sub init {
    my $pkg = shift;
    $farsail = shift;
    $logger = Log::Log4perl->get_logger;
}

sub log_do {
    my ($dbh, $sql) = @_;
    $logger->debug($sql);
    $dbh->do($sql) or $logger->logdie($sql);
}

sub ACTION_load {
}

sub load {
    my $self = shift;
    my ($src, $dest) = @_;
    my $config = $farsail->config;
    my $dest_db = $config->database($dest->{database});
    my ($src_file, $get_row);
    my $dest_delim = $dest->{delimiter} || "\t";
    my $null = $dest->{null} || "";
    if ( ref $src eq 'HASH' && exists $src->{database} ) {
        my $src_dbh = $farsail->db($src->{database});
        my $sth;
        if ( exists $src->{before_sql} ) {
            log_do($src_dbh, $src->{before_sql});
        }
        if ( exists $src->{table} ) {
            $sth = $src_dbh->prepare("select * from $src->{table}") or confess DBI->errstr;
        } else {
            $sth = $src_dbh->prepare($src->{query}) or confess DBI->errstr;
        }
        $sth->execute( @{$src->{bind_params}} );
        if ( $dest_db->{dbd} eq 'Oracle' ) {
            my $fh;
            ($fh, $src_file) = tempfile( SUFFIX => '.dat');
            while ( my $row = $sth->fetchrow_arrayref ) {
                print {$fh} join($dest_delim, map {defined $_ ? $_ : $null} @$row), "\n";
            }
            close($fh);
        } else {
            $get_row = sub {
                my $row = $sth->fetchrow_arrayref;
                if ( !defined $row ) {
                    $sth->finish;
                    return;
                }
                join($dest_delim, map {defined $_ ? $_ : $null} @{$row})."\n"
            };
        }
    } else {
        if ( ref $src eq 'HASH') {
            $src_file = $src->{file};
        } else {
            $src_file = $src;
        }
        if ( $dest_db->{dbd} ne 'Oracle' ) {
            my $fh = Path::Class::File->new($src_file)->open;
            $get_row = sub { readline($fh) };
        }
    }
    my $dbh = $farsail->db($dest->{database});
    if ( exists $dest->{before_sql} ) {
        log_do($dbh, $dest->{before_sql});
    }
    if ( $dest_db->{dbd} eq 'Oracle' ) {
        $self->sqlldr($config->database($dest->{database}), $src_file, $dest->{schema});
    } else {
        log_do($dbh, "COPY $dest->{table} FROM STDIN WITH DELIMITER '$dest_delim'");
        while ( my $row = $get_row->() ) {
            $dbh->pg_putline( $row );
        }
        $dbh->pg_endcopy;
    }
    if ( exists $dest->{after_sql} ) {
        log_do($dbh, $dest->{after_sql});
    }
    if ( ref $src eq 'HASH' && exists $src->{database} && exists $src->{after_sql} ) {
        log_do($farsail->db($src->{database}), $src->{after_sql});
    }
}

sub sqlldr {
    my $self = shift;
    my ($db, $file, $schemafile) = @_;
    my $sqlldr = $farsail->config->get('programs.sqlldr') || 'sqlldr';
    my $cmd = qq($sqlldr control=$schemafile userid=$db->{user}/$db->{password}\@$db->{dbname} data=$file);
    $logger->debug($cmd);
    $farsail->system($cmd) == 0 or confess "load '$file' with schema '$schemafile' failed: $!";
}

1;
